#pragma once
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>

#include <qguiapplication_platform.h>
#include <qpa/qplatformwindow_p.h>
#include <QWindow>
#include <QGuiApplication>

#include "decoder.h"

#define EGL_EGLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#define KeyPress _KeyPress
#define KeyRelease _KeyRelease
#define Bool _Bool
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <GLES2/gl2ext.h>
#undef KeyPress
#undef KeyRelease
#undef Bool

struct FRAME_BUFFER
{
    FRAME_BUFFER(const GLuint frame, const GLuint texture, const GLsizei width, const GLsizei height)
        : frame_(frame)
        , texture_(texture)
        , width_(width)
        , height_(height)
    {
    }

    ~FRAME_BUFFER()
    {
        glDeleteFramebuffers(1, &frame_);
        glDeleteTextures(1, &texture_);
    }

    GLuint frame_;
    GLuint texture_;
    GLsizei width_;
    GLsizei height_;
};

struct EGL_FRAME
{
    EGL_FRAME(const EGLImageKHR image,
//              const MppFrameColorSpace colour_space,
//              const MppFrameColorRange colour_range,
              uint32_t width,
              uint32_t height)
        : image_(image)
//        , colour_space_(colour_space)
//        , colour_range_(colour_range)
        , width_(width)
        , height_(height)
    {
    }

    EGLImageKHR image_;
//    MppFrameColorSpace colour_space_;
//    MppFrameColorRange colour_range_;
    uint32_t width_;
    uint32_t height_;
};

class MyWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT

public:
    MyWidget(QWidget *parent = nullptr);
    ~MyWidget();

    void start();

    // QOpenGLWidget interface
protected:
    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();

private Q_SLOTS:
    void frameReceived(const FrameStruct& frame);

private:
    void init_egl_functions();
    void init_gl_texture(int format, int width, int height,
                         int stride, int shmid, int gl_texture_id,
                         void* imgdata);
    void displayInvalidateGL(int x, int y, int width, int height);
    void do_egl_image(const FrameStruct& frame);
    void destroy_egl_frames();
private:
    QOpenGLShaderProgram* m_program = nullptr;
    QOpenGLShaderProgram* m_oes_program = nullptr;

    QOpenGLVertexArrayObject *m_vao = nullptr;
    QOpenGLBuffer* m_vbo = nullptr;
    QOpenGLBuffer* m_ebo = nullptr;
    int m_oes_texture_sampler_location;
    int m_texture_sampler_location;

    std::unique_ptr<FRAME_BUFFER> m_frame_buffer;

    EGLDisplay m_egl_display;

    FrameStruct m_frame;
    Decoder *m_decoder;

    bool m_flag {false};
};
